//
//  Fonts_AppDelegate.m
//  Fonts
//
//  Created by Georg Seifert on 24.10.08.
//  Copyright __MyCompanyName__ 2008 . All rights reserved.
//

#import "Fonts_AppDelegate.h"
//static void *observeFoundry = (void *)@"observeFoundry";
static void *observeSelection = (void *)@"observeSelection";
#define BasicTableViewDragAndDropDataType @"BasicTableViewDragAndDropDataType"

#import "NSImage+QuickLook.h"
#import "CodingValueTransformer.h"
#import "GSBoolTransformer.h"

@implementation Fonts_AppDelegate

@synthesize previewImages;

- (id) init
{
    if (self = [super init])
    {
		
		NSUserDefaults *Defaults = [NSUserDefaults standardUserDefaults];
		[Defaults registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:
									@"~/Fonts Library/", @"LibraryPath",
									[NSNumber numberWithBool:YES], @"manageFonts", nil]];
		self.previewImages = [NSMutableArray array];
		
		NSValueTransformer *transformer = [[CodingValueTransformer alloc] init];
		[NSValueTransformer setValueTransformer:transformer forName:@"CodingValueTransformer"];
		transformer = [[GSBoolTransformer alloc] init];
		[NSValueTransformer setValueTransformer:transformer forName:@"GSBoolTransformer"];

		
	}
	return self;
}		
/**
    Returns the support folder for the application, used to store the Core Data
    store file.  This code uses a folder named "Fonts" for
    the content, either in the NSApplicationSupportDirectory location or (if the
    former cannot be found), the system's temporary directory.
 */

- (NSString *)applicationSupportFolder {

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
    NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : NSTemporaryDirectory();
    return [basePath stringByAppendingPathComponent:@"Fonts"];
}


/**
    Creates, retains, and returns the managed object model for the application 
    by merging all of the models found in the application bundle.
 */
 
- (NSManagedObjectModel *)managedObjectModel {

    if (managedObjectModel != nil) {
        return managedObjectModel;
    }
	
    managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];    
    return managedObjectModel;
}


/**
    Returns the persistent store coordinator for the application.  This 
    implementation will create and return a coordinator, having added the 
    store for the application to it.  (The folder for the store is created, 
    if necessary.)
 */

- (NSPersistentStoreCoordinator *) persistentStoreCoordinator {

    if (persistentStoreCoordinator != nil) {
        return persistentStoreCoordinator;
    }

    NSFileManager *fileManager;
    NSString *applicationSupportFolder = nil;
    NSURL *url;
    NSError *error;
    
    fileManager = [NSFileManager defaultManager];
    applicationSupportFolder = [self applicationSupportFolder];
    if ( ![fileManager fileExistsAtPath:applicationSupportFolder isDirectory:NULL] ) {
        [fileManager createDirectoryAtPath:applicationSupportFolder attributes:nil];
    }
    
    url = [NSURL fileURLWithPath: [applicationSupportFolder stringByAppendingPathComponent: @"Fonts.xml"]];
    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
    if (![persistentStoreCoordinator addPersistentStoreWithType:NSXMLStoreType configuration:nil URL:url options:nil error:&error]){
        [[NSApplication sharedApplication] presentError:error];
    }    

    return persistentStoreCoordinator;
}


/**
    Returns the managed object context for the application (which is already
    bound to the persistent store coordinator for the application.) 
 */
 
- (NSManagedObjectContext *) managedObjectContext {

    if (managedObjectContext != nil) {
        return managedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        managedObjectContext = [[NSManagedObjectContext alloc] init];
        [managedObjectContext setPersistentStoreCoordinator: coordinator];
    }
    
    return managedObjectContext;
}


/**
    Returns the NSUndoManager for the application.  In this case, the manager
    returned is that of the managed object context for the application.
 */
 
- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window {
    return [[self managedObjectContext] undoManager];
}


/**
    Performs the save action for the application, which is to send the save:
    message to the application's managed object context.  Any encountered errors
    are presented to the user.
 */
 
- (IBAction) saveAction:(id)sender {

    NSError *error = nil;
    if (![[self managedObjectContext] save:&error]) {
        [[NSApplication sharedApplication] presentError:error];
    }
}


/**
    Implementation of the applicationShouldTerminate: method, used here to
    handle the saving of changes in the application managed object context
    before the application terminates.
 */
 
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {

    NSError *error;
    int reply = NSTerminateNow;
    
    if (managedObjectContext != nil) {
        if ([managedObjectContext commitEditing]) {
            if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
				
                // This error handling simply presents error information in a panel with an 
                // "Ok" button, which does not include any attempt at error recovery (meaning, 
                // attempting to fix the error.)  As a result, this implementation will 
                // present the information to the user and then follow up with a panel asking 
                // if the user wishes to "Quit Anyway", without saving the changes.

                // Typically, this process should be altered to include application-specific 
                // recovery steps.  

                BOOL errorResult = [[NSApplication sharedApplication] presentError:error];
				
                if (errorResult == YES) {
                    reply = NSTerminateCancel;
                } 

                else {
					
                    int alertReturn = NSRunAlertPanel(nil, @"Could not save changes while quitting. Quit anyway?" , @"Quit anyway", @"Cancel", nil);
                    if (alertReturn == NSAlertAlternateReturn) {
                        reply = NSTerminateCancel;	
                    }
                }
            }
        } 
        
        else {
            reply = NSTerminateCancel;
        }
    }
    
    return reply;
}


/**
    Implementation of dealloc, to release the retained variables.
 */
 
- (void) dealloc {

    [managedObjectContext release], managedObjectContext = nil;
    [persistentStoreCoordinator release], persistentStoreCoordinator = nil;
    [managedObjectModel release], managedObjectModel = nil;
    [super dealloc];
}
- (void) awakeFromNib {
	UKLog(@" ");
	[window registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
	UKLog(@"managedObjectContext: %@", managedObjectContext);
	//[FontsArrayController addObserver:self forKeyPath:@"arrangedObjects.foundry" options:NSKeyValueObservingOptionOld context:observeFoundry];
	[FontsArrayController addObserver:self forKeyPath:@"selectedObjects" options:NSKeyValueObservingOptionNew context:observeSelection];
	NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
	[nc addObserver:self
		   selector:@selector(updateFonts:)
			   name:NSManagedObjectContextObjectsDidChangeNotification
			 object:nil];
	
	[fontListTableView registerForDraggedTypes:[NSArray arrayWithObjects:BasicTableViewDragAndDropDataType, nil]];
}
- (void)applicationWillTerminate:(NSNotification *)notification {
	
    //NSLog(@"applicationWillTerminate");
}
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender {
	UKLog(@"draggingEntered");
    if ((NSDragOperationCopy & [sender draggingSourceOperationMask]) == NSDragOperationCopy)
    {
        //this means that the sender is offering the type of operation we want
        //return that we want the NSDragOperationGeneric operation that they 
		//are offering
        return NSDragOperationCopy;
    }
    else
    {
        //since they aren't offering the type of operation we want, we have 
		//to tell them we aren't interested
        return NSDragOperationNone;
    }
}
- (void)draggingExited:(id <NSDraggingInfo>)sender {
    //we aren't particularily interested in this so we will do nothing
    //this is one of the methods that we do not have to implement
}
- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender {
    return YES;
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender {
    NSPasteboard *pboard = [sender draggingPasteboard];
	//GSFont * newFont;
	NSFileManager *fileManager = [NSFileManager defaultManager];
	NSDictionary *fileAttributes;
	BOOL schonDa = NO;
    if ( [[pboard types] containsObject:NSFilenamesPboardType] ) {
        NSArray *files = [pboard propertyListForType:NSFilenamesPboardType];
        //int numberOfFiles = [files count];
		for (NSString* currFilePath in files) {
			NSLog(@"Datei angekommen %@", currFilePath);
			fileAttributes = [fileManager fileAttributesAtPath:currFilePath traverseLink:YES];
			NSArray * fileTypes = [NSArray arrayWithObjects:@"otf", @"ttf" , nil];
			//NSLog(@"[currFilePath pathExtension]: %@", [currFilePath pathExtension]);
			
			if ([fileTypes containsObject: [[currFilePath pathExtension] lowercaseString]]) {
				NSLog(@"newDateiPfad: %@", currFilePath);
				schonDa = NO;
//				for (GSFont * currFont in fonts) {
//					//NSLog(@"Dadeipfade: %@", [currFont dateiPfad]);
//					if ([[currFont filePath] isEqual:currFilePath]) {
//						schonDa = YES;
//						break;
//					}
//				}
				if (schonDa) continue;
				
				NSString * fileName = [[currFilePath pathComponents] lastObject];

				//UKLog(@"%@",managedObjectContext);
				
				NSManagedObject * newFont = [NSEntityDescription insertNewObjectForEntityForName:@"font" inManagedObjectContext:managedObjectContext];
				NSURL * FileURL = [NSURL fileURLWithPath:currFilePath ];
				UKLog(@"fileURL: %@", FileURL);
				[newFont setValue: FileURL forKey:@"fileURL"];
				[newFont setValue:fileName forKey:@"fileName"];
				[newFont setValue:[fileName substringToIndex:[fileName length]-[[currFilePath pathExtension] length]-1] forKey:@"family"];
				[newFont setValue:currFilePath forKey:@"filePath" ];
				[managedObjectContext processPendingChanges];
			}
		}
    }
    return YES;
}
- (void)concludeDragOperation:(id <NSDraggingInfo>)sender {
    //re-draw the view with our new data
    //[self setNeedsDisplay:YES];
}
- (void) magageFont:(NSManagedObject*) Font {
	NSUserDefaults *Defaults = [NSUserDefaults standardUserDefaults];
	NSString* LibraryPath = [[Defaults objectForKey:@"LibraryPath"] stringByExpandingTildeInPath];
	NSString* Foundry = [Font valueForKey:@"foundry"];
	if ([Foundry length] < 1) {
		Foundry = @"Unknow Foundry";
	}
	NSString* Family = [Font valueForKey:@"family"];
	if ([Family length] < 1) {
		Family = @"Unknow Family";
	}
	NSString* FileName = [Font valueForKey:@"FileName"];
	if ([FileName length] < 1) {
		NSLog(@"Fehler beim Koperien des Fonts: %@ ", Family);
	}
	
	NSString* Destination = [NSString stringWithFormat:@"%@/%@/%@/%@", LibraryPath, Foundry, Family, FileName];
	NSString* DestinationPath = [[NSString stringWithFormat:@"%@/%@/%@/", LibraryPath, Foundry, Family] stringByExpandingTildeInPath];
	NSString* Source = [[Font valueForKey:@"filePath"] stringByExpandingTildeInPath];
	NSString* SourcePath = [Font valueForKey:@"filePath"];
	SourcePath = [[SourcePath substringToIndex:[SourcePath length]-[FileName length]] stringByExpandingTildeInPath ];

	NSFileManager *fileManager = [NSFileManager defaultManager];
	
	UKLog(@"SourcePath: %@ DestinationPath: %@", SourcePath, DestinationPath);
	BOOL isDirectory;
	//UKLog(@"isDir: %d", [fileManager fileExistsAtPath:destinationPath isDirectory:&isDirectory]);
	BOOL pathExists = [fileManager fileExistsAtPath:DestinationPath isDirectory:&isDirectory];
	UKLog(@"return: %d", isDirectory);
	if (  !pathExists ) {
		//UKLog(@"return: %d", isDirectory);
		UKLog(@"Verzeichnis nicht da");
		
		UKLog(@"createDir: %d", [fileManager createDirectoryAtPath:DestinationPath withIntermediateDirectories:YES attributes:nil error:nil]);
	}
	UKLog(@"Library: %@ prefix: %@",LibraryPath, [Source commonPrefixWithString:LibraryPath options:0]);
	if ([fileManager fileExistsAtPath:Source] && ![fileManager fileExistsAtPath:Destination] ) 
	{
		if ([LibraryPath isEqual: [Source commonPrefixWithString:LibraryPath options:0]]) {
			UKLog(@"moveTo:%@", Destination);
			if ([fileManager movePath:Source toPath:Destination handler:nil]) {
				[Font setValue:Destination forKey:@"filePath"];
			}			
		}
		else {
			UKLog(@"copyTo:%@", Destination);
			if ([fileManager copyPath:Source toPath:Destination handler:nil]) {
				[Font setValue:Destination forKey:@"filePath"];
			}
		}
	}
	NSArray* filesInSourceDir = [fileManager directoryContentsAtPath:SourcePath];
	if ([filesInSourceDir count] == 0) {
		UKLog(@"leeres Verzeichnis");
		[fileManager removeItemAtPath:SourcePath error:nil];
		NSString * foundryPath = [SourcePath substringToIndex:[SourcePath length]-[[SourcePath lastPathComponent] length]-1];
		UKLog(@"foundryPath: %@", foundryPath);
		filesInSourceDir = [fileManager directoryContentsAtPath:foundryPath];
		UKLog(@"pathlength: %d", ([foundryPath length] > [LibraryPath length]));
		UKLog(@"filesInSourceDir: %@", filesInSourceDir);
		BOOL noFileInFoundryDir = [filesInSourceDir count] == 0;
		if ([filesInSourceDir count] == 1) {
			if ([[filesInSourceDir objectAtIndex:0] isEqual:@".DS_Store"]) {
				noFileInFoundryDir = YES;
			}
		}
		if (([foundryPath length] > [LibraryPath length]) && noFileInFoundryDir) {
			UKLog(@"leeres Verzeichnis");
			[fileManager removeItemAtPath:foundryPath error:nil];
		}
	}
}
- (void) deleteFont:(NSManagedObject*) Font {
	
	NSUserDefaults *Defaults = [NSUserDefaults standardUserDefaults];
	NSString* LibraryPath = [[Defaults objectForKey:@"LibraryPath"] stringByExpandingTildeInPath];
	NSString* FileName = [Font valueForKey:@"FileName"];
	NSString* Source = [[Font valueForKey:@"filePath"] stringByExpandingTildeInPath];
	NSString* SourcePath = [Font valueForKey:@"filePath"];
	SourcePath = [[SourcePath substringToIndex:[SourcePath length]-[FileName length]] stringByExpandingTildeInPath ];
	
	NSFileManager *fileManager = [NSFileManager defaultManager];
	
	UKLog(@"SourcePath: %@", SourcePath);
	if ([fileManager fileExistsAtPath:Source]) 
	{
		OSStatus err = FSPathMoveObjectToTrashSync([Source fileSystemRepresentation], nil, kFSFileOperationDefaultOptions);
		if (noErr != err) {
			NSLog(@"something went wrong while deleting font files: %d", err);
		}
	}
	NSArray* filesInSourceDir = [fileManager directoryContentsAtPath:SourcePath];
	if ([filesInSourceDir count] == 0) {
		UKLog(@"leeres Verzeichnis");
		[fileManager removeItemAtPath:SourcePath error:nil];
		NSString * foundryPath = [SourcePath substringToIndex:[SourcePath length]-[[SourcePath lastPathComponent] length]-1];
		UKLog(@"foundryPath: %@", foundryPath);
		filesInSourceDir = [fileManager directoryContentsAtPath:foundryPath];
		UKLog(@"pathlength: %d", ([foundryPath length] > [LibraryPath length]));
		UKLog(@"filesInSourceDir: %@", filesInSourceDir);
		BOOL noFileInFoundryDir = [filesInSourceDir count] == 0;
		if ([filesInSourceDir count] == 1) {
			if ([[filesInSourceDir objectAtIndex:0] isEqual:@".DS_Store"]) {
				noFileInFoundryDir = YES;
			}
		}
		if (([foundryPath length] > [LibraryPath length]) && noFileInFoundryDir) {
			UKLog(@"leeres Verzeichnis");
			[fileManager removeItemAtPath:foundryPath error:nil];
		}
	}
}

- (IBAction) manageFonts:(id) sender {
	
	//UKLog(@"%@", [managedObjectContext registeredObjects]);
	for (id Font in [FontsArrayController arrangedObjects]) {
		//UKLog(@"Font: %@", Font);
		[self magageFont:Font];
	}
}

- (IBAction) setViewMode:(id) sender {
	[viewModeTabView selectTabViewItemAtIndex: [sender selectedSegment]];
	 
}

- (IBAction) toggleActive:(id) sender {
	UKLog(@"%@, %d", sender, [sender selectedSegment]);
	switch( [sender selectedSegment] )
	{
		case 0:	
			[self activate:sender];
			break;
		case 1:
			[self deActivate:sender];
			break;
	}
}
- (IBAction) activate:(id) sender {
	UKLog(@"selecetedFonts: %@", [FontsArrayController valueForKeyPath:@"selectedObjects"]);
	for (id Font in [FontsArrayController valueForKeyPath:@"selectedObjects"]) {
		NSString *fontPath = [Font valueForKeyPath:@"filePath"];
		//ATSFontActivateFromFileReference
		NSURL*fontsURL;
		if(fontsURL = [NSURL fileURLWithPath:fontPath])
		{
			UKLog(@"fontsURL: %@", fontsURL);
			OSStatus status;
			FSRef fsRef;
			CFURLGetFSRef((CFURLRef)fontsURL, &fsRef);
			ATSFontContainerRef oContainer;
			status = ATSFontActivateFromFileReference(&fsRef, kATSFontContextGlobal, kATSFontFormatUnspecified, 
													  NULL, kATSOptionFlagsDoNotNotify, &oContainer);
			UKLog(@"oContainer: %d", oContainer);
			
			if (status != noErr)
			{	
				NSError *err;
				NSString *errorMessage = [NSString stringWithFormat: @"Failed to acivate font: %@", fontPath];
				NSString *localizedMessage = NSLocalizedString(errorMessage, @"");
				NSDictionary *userInfo = [NSDictionary dictionaryWithObject:localizedMessage forKey:NSLocalizedDescriptionKey];
				err = [[NSError alloc] initWithDomain:NSCocoaErrorDomain code:0 userInfo:userInfo];
				NSAlert *alert = [NSAlert alertWithError:err];
				[alert runModal];
			}
			else {
				[Font setValue:[NSNumber numberWithInt:oContainer] forKey:@"active"];
			}
		}
	}
	ATSFontNotify(kATSFontNotifyActionFontsChanged, NULL);
}
- (IBAction) deActivate:(id) sender {
	UKLog(@"selecetedFonts: %@", [FontsArrayController valueForKeyPath:@"selectedObjects"]);
	for (id Font in [FontsArrayController valueForKeyPath:@"selectedObjects"]) {
		if ([[Font valueForKeyPath:@"active"] intValue] == 0) {
			continue;
		}
		UKLog(@"active %d", [[Font valueForKeyPath:@"active"] intValue]);
		OSStatus status;
		status = ATSFontDeactivate ( [[Font valueForKeyPath:@"active"] intValue], 
									nil, 
									kATSOptionFlagsDoNotNotify);
		if (status != noErr)
		{	
			NSError *err;
			NSString *errorMessage = [NSString stringWithFormat: @"Failed to deAcivate font: %@", [Font valueForKeyPath:@"fileName"]];
			NSString *localizedMessage = NSLocalizedString(errorMessage, @"");
			NSDictionary *userInfo = [NSDictionary dictionaryWithObject:localizedMessage forKey:NSLocalizedDescriptionKey];
			err = [[NSError alloc] initWithDomain:NSCocoaErrorDomain code:0 userInfo:userInfo];
			NSAlert *alert = [NSAlert alertWithError:err];
			[alert runModal];
		}
		else {
			[Font setValue:[NSNumber numberWithBool:NO] forKey:@"active"];
		}
	}
	ATSFontNotify(kATSFontNotifyActionFontsChanged, NULL);
}
- (IBAction) info:(id) sender {
}

- (void) updateFonts:(id) sender {
	UKLog(@"sender: %@", [sender userInfo]);
	for (id Font in [[sender userInfo] objectForKey:@"updated"]) {
		[self magageFont:Font];
	}
	for (id Font in [[sender userInfo] objectForKey:@"inserted"]) {
		[self magageFont:Font];
	}
	for (id Font in [[sender userInfo] objectForKey:@"deleted"]) {
		[self deleteFont:Font];
	}
}
- (void) updatePreview:(id) sender {
	//UKLog(@"selecetedFonts: %@", [FontsArrayController valueForKeyPath:@"selectedObjects.filePath"]);
	NSMutableArray *newPreviews = [NSMutableArray array];
	NSSize size = NSMakeSize(300, 50);
	for (id path in [FontsArrayController valueForKeyPath:@"selectedObjects.filePath"]) {
		[newPreviews addObject:[NSImage imageWithPreviewOfFileAtPath:path ofSize:(NSSize)size asIcon:NO]];
	}
	//UKLog(@"%@",newPreviews);
	self.previewImages = newPreviews;
	//UKLog(@"%@",self.previewImages);
}

- (IBAction) chooseLibraryPath:(id) sender {
	NSOpenPanel* openDlg = [NSOpenPanel openPanel];
	[openDlg setCanChooseFiles:NO];
	[openDlg setAllowsMultipleSelection:NO];
	[openDlg setCanChooseDirectories:YES];
	NSUserDefaults *Defaults = [NSUserDefaults standardUserDefaults];
	if ( [openDlg runModalForDirectory:[Defaults objectForKey:@"LibraryPath"] file:nil types:nil] == NSOKButton ){
		[Defaults setObject:[[openDlg filenames] objectAtIndex:0] forKey:@"LibraryPath"];
	}	
}
- (IBAction) defaultLibraryPath:(id) sender {
	NSUserDefaults *Defaults = [NSUserDefaults standardUserDefaults];
	[Defaults setObject:@"~/Fonts Library/" forKey:@"LibraryPath" ];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
	//UKLog(@"keyPath: %@ object: %@ change: %@",keyPath, [object selectedObjects] , change);
	if (context == observeSelection) {
		[self updatePreview:nil];
	}
}

- (BOOL)tableView:(NSTableView *)tv writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard*)pboard {
	// Drag and drop support
	NSData *data = [NSKeyedArchiver archivedDataWithRootObject:rowIndexes];
	[pboard declareTypes:[NSArray arrayWithObject:BasicTableViewDragAndDropDataType] owner:self];
	[pboard setData:data forType:BasicTableViewDragAndDropDataType];
	return YES;
}
@end
